package com.ziyun.pop.modules.capital.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.foxinmy.weixin4j.util.StringUtil;
import com.utility.JsonUtils;
import com.ziyun.pop.common.utils.ChineseCalendarUtils;
import com.ziyun.pop.common.utils.HttpClientUtil;
import com.ziyun.pop.modules.capital.dao.MerchantApplyCashDao;
import com.ziyun.pop.modules.capital.entity.*;
import com.ziyun.pop.modules.capital.service.*;
import io.renren.common.exception.RRException;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.modules.sys.entity.SysUserEntity;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


@Service("merchantApplyCashService")
public class MerchantApplyCashServiceImpl extends ServiceImpl<MerchantApplyCashDao, MerchantApplyCashEntity> implements MerchantApplyCashService {

    @Autowired
    private MerchantApplyCashItemsService merchantApplyCashItemsService;

    @Autowired
    private RemittanceMerchantsService remittanceMerchantsService;

    @Autowired
    private MerchantApplyLogService merchantApplyLogService;

    @Autowired
    private MerchantOrderAccountService merchantOrderAccountService;

    @Autowired
    private MerchantPurseService merchantPurseService;

    //申请提现地址
    @Value("${umf.applyAddress}")
    private String applyAddress;
    // 申请提现回调地址
    @Value("${umf.applyNotifyAddress}")
    private String applyNotifyAddress;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        IPage<MerchantApplyCashEntity> page = this.page(
                new Query<MerchantApplyCashEntity>(params).getPage(),
                new QueryWrapper<MerchantApplyCashEntity>()
                        .eq("seller_id", params.get("sellerId"))
                        .eq("merchant_type", params.get("merchantType"))
                        .eq(!StringUtils.isEmpty(params.get("id")), "id", params.get("id"))
                        .eq((!StringUtils.isEmpty(params.get("applyStatus"))&& !params.get("applyStatus").equals(-1) ),"apply_status", params.get("applyStatus"))
                        .like(!StringUtils.isEmpty(params.get("payNo")), "pay_no",  params.get("payNo"))
                        .orderByDesc("apply_time")

        );

        return new PageUtils(page);
    }


    /**
     * 申请提现
     *
     * @param params
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyCash(Map<String, Object> params) {
        // 获取商户类型 0 商家 1 工厂
        Integer merchantType = Integer.parseInt(params.get("merchantType").toString());

        Integer sellerId = Integer.parseInt(params.get("sellerId").toString());

        //提现订单ids
        List orderAccountIds = JsonUtils.string2Collection(params.get("orderAccountIds").toString(), List.class, Integer.class) ;

        BigDecimal totalMoney = new BigDecimal(params.get("totalMoney").toString());

        // 查询商户 是否配置银行卡相关信息
        RemittanceMerchantsEntity remittanceMerchants = this.remittanceMerchantsService.getOne(
                new QueryWrapper<RemittanceMerchantsEntity>()
                        .eq("seller_id", sellerId)
                        .eq("merchant_type", merchantType)
        );
        if (remittanceMerchants == null) {
            throw new RRException("未查询到该商户银行卡信息!");
        } else if (StringUtil.isEmpty(remittanceMerchants.getReceiverAccount())
                || StringUtil.isEmpty(remittanceMerchants.getReceiverName())
                || StringUtil.isEmpty(remittanceMerchants.getReceiverAccountBranch())) {
            throw new RRException("未配置银行卡等相关信息！");
        }

        // 处理订单状态 此处需要将订单状态更改为操作中 防止多个账号同时操作
        Map<String, Object> whereParams = new HashMap<>();
        whereParams.put("orderAccountIds", orderAccountIds);
        whereParams.put("fundState", 99);
        whereParams.put("whereFundState", 0);
        int size = this.merchantOrderAccountService.updateBatchByParams(whereParams);

        if (size < 1) {
            throw new RRException("更新订单操作状态99失败，请刷新后重试!");
        }

        // 重新查询订单详情 进行计算
        List<MerchantOrderAccountEntity> merchantOrderAccountList = this.merchantOrderAccountService.list(new QueryWrapper<MerchantOrderAccountEntity>()
                .in("order_account_id", orderAccountIds)
                .eq("fund_state", 99));
        if (merchantOrderAccountList.size() != orderAccountIds.size()) {
            throw new RRException("订单状态存在异常,请刷新后重试!");
        }

        // 服务端计算价格
        BigDecimal totalServerPrice = BigDecimal.ZERO;
        if (merchantType.intValue() == 0) { // 小b 算价
            totalServerPrice = this.calculatingSmallBPrice(merchantOrderAccountList, sellerId);
        } else if (merchantType.intValue() == 1) { // 工厂算价
            totalServerPrice = this.calculatingFactoryPrice(merchantOrderAccountList, sellerId);
        }

        totalMoney = totalMoney.setScale(3, BigDecimal.ROUND_HALF_UP);
        // 判断前后台金额时候一致
        if (totalServerPrice.compareTo(totalMoney) != 0) {
            throw new RRException("提现总金额异常!");
        }

        // 准备生成 申请单主表
        MerchantApplyCashEntity merchantApplyCashMain = new MerchantApplyCashEntity();
        merchantApplyCashMain.setSellerId(sellerId);
        merchantApplyCashMain.setMerchantType(merchantType);
        merchantApplyCashMain.setMerchantName(merchantOrderAccountList.get(0).getSellerName());//任意一个单据供应商名称即可
        merchantApplyCashMain.setApplyStatus(0); //0:待审核
        merchantApplyCashMain.setApplyMoney(totalServerPrice);
        merchantApplyCashMain.setApplyUser(params.get("userName").toString());
        merchantApplyCashMain.setApplyTime(new Date());
        merchantApplyCashMain.setDelFlag(0);
        // 插入主表
        this.save(merchantApplyCashMain);

        if (merchantApplyCashMain.getId() == null) {
            throw new RRException("生成申请单主表异常,请联系管理员!");
        }

        // 组装明细
        List<MerchantApplyCashItemsEntity> itemList = this.assemblyApplyCashDetail(merchantApplyCashMain.getId(), merchantOrderAccountList);
        try {
            this.merchantApplyCashItemsService.saveBatch(itemList,itemList.size());
        } catch (Exception e) {
            throw new RRException("生成订单明细异常,请联系管理员!" + e.getCause());
        }

        // 更新状态为 已提交
        whereParams.put("orderAccountIds", orderAccountIds);
        whereParams.put("fundState", 2);//打款中
        whereParams.put("whereFundState", 99);
        int rNumber = this.merchantOrderAccountService.updateBatchByParams(whereParams);
        if (rNumber < 1) {
            throw new RRException("更新订单操作状态失败，请联系管理员!");
        }

        //写入 资金表
        MerchantPurseEntity merchantPurse = new MerchantPurseEntity();
        merchantPurse.setMerchantType(merchantType);
        merchantPurse.setSellerId(sellerId);
        merchantPurse.setCashAmountPresent(totalServerPrice);
        this.merchantPurseService.updatePurse(merchantPurse);

    }

    /**
     * 组装
     * @param id
     * @param merchantOrderAccountList
     * @return
     */
    private List<MerchantApplyCashItemsEntity> assemblyApplyCashDetail(Integer id, List<MerchantOrderAccountEntity> merchantOrderAccountList) {

        List<MerchantApplyCashItemsEntity> items = new ArrayList<MerchantApplyCashItemsEntity>();

        for(MerchantOrderAccountEntity merchantOrderAccount : merchantOrderAccountList){
            MerchantApplyCashItemsEntity temp = new MerchantApplyCashItemsEntity();
            temp.setApplyCashId(id);
            temp.setOrderAccountId(merchantOrderAccount.getOrderAccountId());
            temp.setIsAllot(merchantOrderAccount.getOrderAllotId() == null?0:1);
            temp.setOrderStatus(merchantOrderAccount.getStatus());
            temp.setOrderCreateTime(merchantOrderAccount.getOrderCreateTime());
            temp.setTotalAmount(merchantOrderAccount.getTotalAmount());
            temp.setCostFreight(merchantOrderAccount.getCostFreight());
            temp.setDiscount(merchantOrderAccount.getDiscount());
            temp.setPmtGoods(merchantOrderAccount.getPmtGoods());
            temp.setPmtOrder(merchantOrderAccount.getPmtOrder());
            temp.setPmtRandom(merchantOrderAccount.getPmtRandom());
            temp.setPayableAmount(merchantOrderAccount.getPayableAmount());
            temp.setPayed(merchantOrderAccount.getPayed());
            temp.setPayment(merchantOrderAccount.getPayment());
            temp.setPaymentTime(merchantOrderAccount.getPaymentTime());
            temp.setFinishTime(merchantOrderAccount.getReceivedTime());
            items.add(temp);
        }
        return items;
    }

    /**
     * 计算小b 提现 服务端价格
     * @param merchantOrderAccountList
     * @param sellerId
     * @return
     */
    private BigDecimal calculatingSmallBPrice(List<MerchantOrderAccountEntity> merchantOrderAccountList, Integer sellerId) {
        //遍历订单 计算价格
        BigDecimal totalAmount = BigDecimal.ZERO;
          /*
               * 奖励金政策发生变化， 提现规则响应变化
               * 1.2018.11.16: 23:59:59  之前的订单 按照 商品总额+运费+随机立减 计算提现金额
               * 2.2018.11.16: 23:59:59  之后的订单 按照 商品总额+运费 计算提现金额
               * 3.一次申请提现 下单日期不能夸 2018.11.16 天
            */
        List<Integer> gtDay = new ArrayList<>(); //大于指定日期订单数
        List<Integer> eltDay = new ArrayList<>(); // 小于等于指定日期订单数
        for (MerchantOrderAccountEntity merchantOrderAccount : merchantOrderAccountList){
            //商家提现 计算可提现金额 商品总额 + 运费 + 随机立减
            BigDecimal lineAmount =BigDecimal.ZERO;
            // 判断日期 与 2018.11.16: 23:59:59 比较
            Date orderCreateTime = merchantOrderAccount.getOrderCreateTime();
            Date specifiedTime = DateUtils.stringToDate("2018-11-16 23:59:59",DateUtils.DATE_TIME_PATTERN);
            if(orderCreateTime.getTime() > specifiedTime.getTime()){
                gtDay.add(1);
            }else {
                eltDay.add(1);
            }
            if(gtDay.size()>0 && eltDay.size()>0){
                throw new RRException(" 2018年11月16日24:00之后的金额需单独提现 !<br>订单【"+ merchantOrderAccount.getOrderAccountId()+"】");
            }

            boolean isAllot = false;
            if (merchantOrderAccount.getOrderAllotId()!= null){
                isAllot = true;
            }

            if (eltDay.size() >0 && isAllot == false){
                lineAmount =   lineAmount.add(merchantOrderAccount.getTotalAmount()).add(merchantOrderAccount.getCostFreight())
                        .add(merchantOrderAccount.getPmtRandom());
            }

            if(gtDay.size() >0 && isAllot == false){
                lineAmount =   lineAmount.add(merchantOrderAccount.getTotalAmount()).add(merchantOrderAccount.getCostFreight());
            }

            if(isAllot){ //分配订单 商品总额+运费+折扣
                lineAmount =   lineAmount.add(merchantOrderAccount.getTotalAmount()).add(merchantOrderAccount.getCostFreight())
                        .add(merchantOrderAccount.getDiscount());
            }

            totalAmount = totalAmount.add(lineAmount);
        }
        totalAmount =  totalAmount.setScale(3, BigDecimal.ROUND_HALF_UP);
        return totalAmount;
    }

    /**
     * 计算工厂 提现 服务端价格
     * @param merchantOrderAccountList
     * @param sellerId
     * @return
     */
    private BigDecimal calculatingFactoryPrice(List<MerchantOrderAccountEntity> merchantOrderAccountList, Integer sellerId) {
        //遍历订单 计算价格
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (MerchantOrderAccountEntity merchantOrderAccount : merchantOrderAccountList){
            //工厂提现 计算可提现金额 商品总额 + 运费 + 调价
            BigDecimal lineAmount =BigDecimal.ZERO;
            lineAmount =   lineAmount.add(merchantOrderAccount.getTotalAmount()).add(merchantOrderAccount.getDiscount())
                    .add(merchantOrderAccount.getPmtRandom());

            totalAmount = totalAmount.add(lineAmount);
        }
        totalAmount =  totalAmount.setScale(3, BigDecimal.ROUND_HALF_UP);
        return totalAmount;
    }



    /**
     * 计算提现单设计汇费 非实时接口
     *
     * @param id
     * @param currentDate
     * @return
     */
    private BigDecimal computeFee(Integer id, Date currentDate) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 首先计算预估到账天数
        int dayOfNumber = 0;
        // 1.计算当前日期是否为工作日
        if (ChineseCalendarUtils.isWorkDay(currentDate)) { // 是工作日

            // 判断是否大于16:30
            if (!ChineseCalendarUtils.compareHourMinute(currentDate, "16:30:00")) {
                // 大于 则计算 距离当前日期第二天的 天数
                dayOfNumber = ChineseCalendarUtils.getNextWorkDays(currentDate);

            } else { // 小于 则是当天到账
                dayOfNumber = 0;
            }
        } else {
            // 非工作日 则计算下一个工作日 日距离当前天数
            dayOfNumber = ChineseCalendarUtils.getNextWorkDays(currentDate);
        }

        //计算出预计到账日期
        Date expectDate = ChineseCalendarUtils.addDate(currentDate, dayOfNumber);

        // 循环订单明细 计算汇费
        List<MerchantApplyCashItemsEntity> merchantApplyCashItemsEntityList = new ArrayList<>();

        if (CollectionUtils.isEmpty(merchantApplyCashItemsEntityList)) {
            throw new RRException("提现单明细异常!");
        }

        BigDecimal totalFee = BigDecimal.ZERO;
        BigDecimal totalMoney = BigDecimal.ZERO;
        List<MerchantApplyCashItemsEntity> updateItemList = new ArrayList<>();
        for (MerchantApplyCashItemsEntity merchantApplyCash : merchantApplyCashItemsEntityList) {
            if (merchantApplyCash.getIsAllot() == 1) { //分配订单 无需汇费
                continue;
            }

            // 取出订单完成日期
            Date finishTime = merchantApplyCash.getFinishTime();

            // 比较预计到账日期与订单完成日期 时间差 计算汇费
            int differenceDay = ChineseCalendarUtils.getDifferenceDays(expectDate, finishTime);

            //计算汇率
            double percentage = this.getPercentage(differenceDay);

            if (percentage == -1) {
                throw new RRException("订单日期异常,请联系管理员!");
            }

            // 商品总金额
            BigDecimal goodsTotalAmount = merchantApplyCash.getTotalAmount();
            // 运费
            BigDecimal costFreight = merchantApplyCash.getCostFreight();
            // 随机立减
            BigDecimal pmtRandom = merchantApplyCash.getPmtRandom();

            // 提现金额
            BigDecimal putForwardAmount = goodsTotalAmount.add(costFreight).add(pmtRandom);
            totalMoney = totalMoney.add(putForwardAmount);

            // 提现费用
            BigDecimal putForwardFee = putForwardAmount.multiply(new BigDecimal(percentage));
            putForwardFee = putForwardFee.setScale(3, BigDecimal.ROUND_HALF_DOWN);

            //组装明细提现费用
            MerchantApplyCashItemsEntity itemsUpdate = new MerchantApplyCashItemsEntity();
            itemsUpdate.setId(merchantApplyCash.getId());
            itemsUpdate.setFee(putForwardFee);
            updateItemList.add(itemsUpdate);

            // 提现总费用
            totalFee = totalFee.add(putForwardFee);

        }
        //批量更细明细提现费用
        if (updateItemList.size() > 0) {
            this.merchantApplyCashItemsService.updateBatchById(updateItemList);
        }


        // 更新主表 提现总费用 预计到账日期
        MerchantApplyCashEntity merchantApplyCashEntity = new MerchantApplyCashEntity();
        merchantApplyCashEntity.setId(id);
        merchantApplyCashEntity.setApplyFee(totalFee);
        merchantApplyCashEntity.setExpectDate(expectDate);
        this.updateById(merchantApplyCashEntity);

        return totalFee;
    }

    /**
     * 根据天数计算汇费差距
     *
     * @param differenceDay
     * @return
     */
    private double getPercentage(int differenceDay) {
        double percentage = 0;
        switch (differenceDay) {
            case 0:
                percentage = -1;
                break;
            case 1:
                percentage = -1;
                break;
            case 2:
                percentage = 0.007;
                break;
            case 3:
                percentage = 0.006;
                break;
            case 4:
                percentage = 0.005;
                break;
            case 5:
                percentage = 0.004;
                break;
            case 6:
                percentage = 0.003;
                break;
            default:
                percentage = 0;
                break;

        }

        return percentage;
    }

    /**
     * 赋值 请求json
     *
     * @param amount  金额
     * @param purpose 秒速
     * @param date    下单日期
     * @param rmer    银行卡相关信息
     * @return
     */
    private Map<String, String> setApplyData(BigDecimal amount, String purpose, String date, RemittanceMerchantsEntity rmer) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("amount", amount.toString()); //  付款金额 -汇费
        map.put("bank_brhname", rmer.getReceiverAccountBranch()); // 开户行支行全称
        map.put("branch_bank_code", rmer.getReceiverAccountNumber()); // 支行联行号
        map.put("checkFlag", "1"); // 付款实时和非实时标识 0 实时 1 非实时
        map.put("city_name", rmer.getReceiverCity()); // 市
        map.put("com_amt_type", ""); // 手续费类型
        map.put("cut_fee_type", ""); // 手续费扣款类型
        map.put("expire_time", ""); // 订单过期时长
        map.put("goods_inf", ""); // 商品描述
        map.put("identity_code", rmer.getReceiverCredential()); // 收款方平台预留证件号码
        map.put("identity_holder", rmer.getReceiverName()); // 证件持有人真实姓名
        map.put("identity_type", "01"); // rmer.getCredentialType() //收款方证件类型
        map.put("mer_date", date); // 订单日期,格式YYYYMMDD,订单日期必须为当日
        map.put("mer_id", "50956"); // 商户号
        map.put("mer_priv", ""); // 商户私有域
        map.put("mobile_no", rmer.getReceiverMobile()); // 收款方手机号
        map.put("notify_url", applyNotifyAddress); // 服务器异步通知页面路径 "http://61.183.151.86:9999/a/merchantCash/notifyUrl"
        map.put("order_id", this.getPaymentsId()); // 订单号
        map.put("prov_name", rmer.getReceiverProvince()); // 省
        map.put("purpose", purpose); // 摘要
        map.put("recv_account", rmer.getReceiverAccount()); // 收款方账号
        map.put("recv_account_type", "00"); // 收款方账户类型
        map.put("recv_bank_acc_pro", rmer.getReceiverBankAccountPro()); // 收款方账户属性
        map.put("recv_gate_id", rmer.getReceiverGateId()); // 收款方账户的发卡行
        map.put("recv_user_name", rmer.getReceiverName()); // 收款方户名
        map.put("user_ip", ""); // 用户IP
        return map;
    }

    /**
     * TODO 后期考虑单号重复问题
     * 获取支付单号
     *
     * @return
     */
    private static String getPaymentsId() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmm");
        String payMentsId = "AP-" + dateFormat.format(new Date()) + (int) (Math.random() * 1000000);
        return payMentsId;
    }

}
